// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu

// order latency dataset dumper for 1 symbol
// this requires (1) trade feed and (2) og log

#include "coin2/support/order_latency/dumper.h"

#include <memory>
#include <string>

#include <cxxopts.hpp>
#include <fmt/format.h>

#include "coin2/app/driver.h"
#include "coin2/app/driver.pb.h"
#include "coin2/base/config/app_config.h"
#include "coin2/base/config/args.h"
#include "coin2/base/log.h"
#include "coin2/exchange/base/symbology/product.h"

using coin2::app::DriverConfig;

DriverConfig parse_cli(
    int argc,
    char* argv[],
    std::string* mea,
    std::string* relative_symbol,
    std::string* absolute_symbol) {
  // you have 2 options to provide flags.
  // 1. --driver
  // 2. --machine --fastfeed --...
  // mixing these 2 is discouraged.

  DriverConfig app;
  cxxopts::Options opt("OrderLatency Dumper", "Dump dataset for Order Latency");

  coin2::base::config::AddIntervalOptions(&opt);                         // --start --end --duration
  opt.add_options()                                                      // add options
      ("feed_machine", "feed machine", cxxopts::value<std::string>())    //
      ("mea", "M.E.A", cxxopts::value<std::string>())                    //
      ("recipe", "recipe", cxxopts::value<std::string>())                //
      ("strat_account", "strat account", cxxopts::value<std::string>())  //
      ("strat_machine", "order machine", cxxopts::value<std::string>())  //
      ("product", "a norm symbol", cxxopts::value<std::string>());       //

  auto res = opt.parse(argc, argv);
  for (const auto& s : std::vector<std::string>{
           "feed_machine",
           "mea",
           "recipe",
           "strat_account",
           "strat_machine",
           "product"}) {
    CHECK_THROW(res.count(s) == 1) << "missing --" << s;
  }

  // feed
  {
    auto& exchanges = *app.mutable_feed()->mutable_exchanges();
    auto& exchange = exchanges[res["mea"].as<std::string>()];

    exchange.set_mea(res["mea"].as<std::string>());
    exchange.set_recipe(res["recipe"].as<std::string>());
    exchange.set_type(coin2::exchange::feed::FeedSystemType::FEED_SYSTEM_TYPE_ARCHIVE);
    exchange.mutable_products()->add_norms(res["product"].as<std::string>());
    exchange.mutable_archive()->set_archive_type(coin2::exchange::feed::ArchiveConfig::FASTFEED);
    exchange.mutable_archive()->set_machine(res["feed_machine"].as<std::string>());
  }

  // order
  {
    auto& exchanges = *app.mutable_order()->mutable_exchanges();
    auto& exchange = exchanges[res["mea"].as<std::string>()];

    exchange.set_mea(res["mea"].as<std::string>());
    exchange.set_type(coin2::exchange::order::OrderSystemType::ORDER_SYSTEM_TYPE_ARCHIVE);
    exchange.mutable_products()->add_norms(res["product"].as<std::string>());
    exchange.mutable_archive()->set_owner(res["strat_account"].as<std::string>());
    exchange.mutable_archive()->set_machine(res["strat_machine"].as<std::string>());
  }

  *mea = res["mea"].as<std::string>();

  coin2::base::config::ParseIntervalOptions(
      res,
      app.mutable_feed()->mutable_common()->mutable_archive()->mutable_interval());
  coin2::base::config::ParseIntervalOptions(
      res,
      app.mutable_order()->mutable_common()->mutable_archive()->mutable_interval());

  auto start_end =
      coin2::base::config::FromIntervalConfig(app.order().common().archive().interval());

  coin2::exchange::symbology::ProductRequest req;
  req.set_mea(*mea);
  req.set_norm(res["product"].as<std::string>());
  auto prod = ResolveProductRequest(req, start_end.first);
  *absolute_symbol = prod->absolute_norm();
  *relative_symbol = prod->relative_norm();

  return app;
}

int main(int argc, char* argv[]) {
  std::string mea;
  std::string relative_symbol;
  std::string absolute_symbol;
  coin2::app::DriverConfig app = parse_cli(argc, argv, &mea, &relative_symbol, &absolute_symbol);

  std::unique_ptr<LatencyModelDatasetDumper> dumper(new LatencyModelDatasetDumper(absolute_symbol));
  coin2::app::Driver driver(app, dumper.get());
  driver.Run();

  // out/latency-dataset/order-submit/Futures.Huobi.v1:BTC-USD.QUARTER.h5
  // out/latency-dataset/order-cancel/Futures.Huobi.v1:BTC-USD.QUARTER.h5

  std::experimental::filesystem::path order_submit_h5 =
      fmt::format("out/latency-dataset/order-submit/{}:{}.h5", mea, relative_symbol);
  std::experimental::filesystem::path order_cancel_h5 =
      fmt::format("out/latency-dataset/order-cancel/{}:{}.h5", mea, relative_symbol);

  dumper->SaveToFiles(order_submit_h5, order_cancel_h5);

  return 0;
}
